/**
 * A simple hack to invoke Expose instead of standard application switcher
 * using the COMMAND-TAB
 *
 * Author: Sandip V. Chitale (sandipchitale@gmail.com)
 * Version: 1.0
 */

#include <ApplicationServices/ApplicationServices.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h>
#include <stdio.h>


CGEventRef EventTap(CGEventTapProxy proxy,
					CGEventType type,
					CGEventRef event,
					void *refcon)
{
	CGEventFlags *oldFlags = (CGEventFlags *)refcon; 
	switch (type) {
		case kCGEventKeyDown:
			/*
			printf("Got key %s event, keycode 0x%04LX.\n",
				   
				   type == kCGEventKeyDown ? "down" : "up",
				   
				   CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
			
			//*/
			// Is the COMMAND down?
			if (((*oldFlags) & 0x100008) != 0) {
				// F9
				if (CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == 0x0065) {
					exit(0);
				}
				// TAB ?
				if (CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == 0x0030) {
					pid_t pid = fork();
					if(pid == 0) {
						// In child - run Expose
						execl("/usr/bin/open", "-a", "/Applications/Utilities/Expose.app", NULL);
//						execl("/usr/bin/open", "-a", "/Library/Scripts/Switcher.app", NULL);
					}
					// Consume the event in the perent
					return NULL;
				}
			}
			
			break;
		case kCGEventFlagsChanged: {
			CGEventFlags new = CGEventGetFlags(event);
			/*
			CGEventFlags changed = *oldFlags ^ new; 
			
			printf("Got flags changed event. Old flags 0x%llX, new 0x%llX, changed 0x%llX.\n",
				   
				   *oldFlags, new, changed);
			
			*/
			*oldFlags = new;
			break;
		}
	}
	
	return event; 
}

int main(int argc, char **argv)
{
	
	CGEventFlags oldFlags =
	CGEventSourceFlagsState(kCGEventSourceStateCombinedSessionState);
	
	CFMachPortRef eventTapPort = 
	CGEventTapCreate(kCGSessionEventTap, 
					 kCGHeadInsertEventTap,
					 0,
					 CGEventMaskBit(kCGEventKeyDown) |
					 CGEventMaskBit(kCGEventKeyUp) |
					 CGEventMaskBit(kCGEventFlagsChanged), 
					 EventTap,
					 &oldFlags);
	
	CFRunLoopSourceRef eventTapSource =
	CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
								  eventTapPort, 
								  0);
	CFRelease(eventTapPort);
	
	CFRunLoopAddSource(CFRunLoopGetCurrent(),
					   eventTapSource,
					   kCFRunLoopCommonModes);
	CFRelease(eventTapSource); 
	
	CFRunLoopRun();

}
